package com.duojuhe.security.shiro;

import com.duojuhe.security.shiro.filter.ShiroAdminControlFilter;
import com.duojuhe.security.shiro.filter.ShiroCommonControlFilter;
import com.duojuhe.security.shiro.filter.ShiroPermissionFilter;
import com.duojuhe.security.shiro.filter.ShiroPublicControlFilter;
import com.duojuhe.security.shiro.resources.ResourcesService;
import com.duojuhe.common.constant.ApiPathConstants;
import com.duojuhe.common.constant.SingleStringConstant;
import com.duojuhe.coremodule.system.entity.SystemMenu;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;

import javax.annotation.Resource;
import javax.servlet.Filter;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * shiro 基本过滤配置
 *
 * @date 2018/2/9.
 */
@Configuration
@Slf4j
public class ShiroConfig {
    @Resource
    private ResourcesService resourcesService;

    private static final String PREMISSION_STRING = "adminControl,user,perms[\"{0}\"]";
    /**
     * ShiroFilterFactoryBean 处理拦截资源文件问题。
     * 注意：单独一个ShiroFilterFactoryBean配置是或报错的，以为在
     * 初始化ShiroFilterFactoryBean的时候需要注入：SecurityManager
     * Filter Chain定义说明 1、一个URL可以配置多个Filter，使用逗号分隔 2、当设置多个过滤器时，全部验证通过，才视为通过
     * 3、部分过滤器可指定参数，如perms，roles
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 设置自定义过滤器
        setFilters(shiroFilterFactoryBean);
        // 权限控制map.
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        // 通用接口token验证
        filterChainDefinitionMap.put("/" + ApiPathConstants.COMMON_PATH + "/**", "commonControl,user");
        // 后台接口菜单权限控制
        putAdminAuthorization(filterChainDefinitionMap);
        filterChainDefinitionMap.put("/**", "publicControl,anon");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }


    /**
     * 后台权限配置
     */
    private void putAdminAuthorization(Map<String, String> filterChainDefinitionMap) {
        List<SystemMenu> menuList = resourcesService.querySystemMenuAll();
        for (SystemMenu authority : menuList) {
            if (StringUtils.isEmpty(authority.getMenuCode()) || StringUtils.isEmpty(authority.getApiUrl())) {
                continue;
            }
            String[] permArr = authority.getApiUrl().split(SingleStringConstant.COMMA);
            for(String apiPath : permArr){
                filterChainDefinitionMap.put("/" + apiPath, MessageFormat.format(PREMISSION_STRING, authority.getMenuCode()));
            }
        }
        filterChainDefinitionMap.put("/" + ApiPathConstants.ADMIN_PATH + "/**", "adminControl,user");
    }


    /**
     * 设置自定义过滤器
     */
    private void setFilters(ShiroFilterFactoryBean shiroFilterFactoryBean) {
        // 添加自己的过滤器
        Map<String, Filter> filterMap = new HashMap<String, Filter>(1);
        //权限验证
        filterMap.put("perms", shiroPermissionFilter());
        //admin后台接口token校验
        filterMap.put("adminControl",shiroAdminControlFilter());
        //通用接口token校验
        filterMap.put("commonControl",shiroCommonControlFilter());
        //通用接口token校验
        filterMap.put("publicControl",shiroPublicControlFilter());
        shiroFilterFactoryBean.setFilters(filterMap);
    }


    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置realm.
        securityManager.setRealm(myShiroRealm());
        // 设置Subject工厂
        securityManager.setSubjectFactory(subjectFactory());
       // 禁用Session作为存储策略的实现。
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);
        return securityManager;
    }

    @Bean
    public StatelessDefaultSubjectFactory subjectFactory() {
        return new StatelessDefaultSubjectFactory();
    }


    /**
     * 身份认证realm;
     *
     * @return
     */
    @Bean
    public ShiroRealm myShiroRealm() {
        return new ShiroRealm();
    }


    /**
     * 开启shiro aop注解支持.
     * 使用代理方式;所以需要开启代码支持;
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }


    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }


    /**
     * 判断登录后有没有权限
     *
     * @return
     */
    @Bean
    public ShiroPermissionFilter shiroPermissionFilter() {
        return  new ShiroPermissionFilter();
    }



    /**
     * 判断admin登录后有没有权限
     *
     * @return
     */
    @Bean
    public ShiroAdminControlFilter shiroAdminControlFilter() {
        return  new ShiroAdminControlFilter();
    }


    /**
     * 判断有没有公共接口权限
     *
     * @return
     */
    @Bean
    public ShiroCommonControlFilter shiroCommonControlFilter() {
        return  new ShiroCommonControlFilter();
    }

    /**
     * 无须登录的公共拦截接口
     *
     * @return
     */
    @Bean
    public ShiroPublicControlFilter shiroPublicControlFilter() {
        return  new ShiroPublicControlFilter();
    }


    @Bean
    public DefaultSessionStorageEvaluator defaultSessionStorageEvaluator () {
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        return defaultSessionStorageEvaluator;
    }
}
